/*
 * DIM-SUM操作系统 -- 精确计数实现
 *
 * Copyright (C) 2023 国科础石(重庆)软件有限公司
 *
 * 作者: Dong Peng <w-pengdong@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#include <linux/compiler.h>
#include <dim-sum/accurate_counter.h>
#include <dim-sum/bug.h>
#include <dim-sum/uaccess.h>


#include <asm/barrier.h>

long arch_accurate_add(long i, struct accurate_counter *v)
{
	unsigned long tmp;
	long result;

	asm volatile(
		"1:	lr.d	%0, %2\n"
		"	add	%0, %0, %3\n"
		"	sc.d	%1, %0, %2\n"
		"	bnez	%1, 1b"
			: "=&r" (result), "=&r" (tmp), "+A" (v->counter)
			: "Ir" (i)
			: "memory");

	/*  */
	smp_mb();
	return result;
}

long arch_accurate_sub(long i, struct accurate_counter *v)
{
	unsigned long tmp;
	long result;

	asm volatile(
		"1:	lr.d	%0, %2\n"
		"	sub	%0, %0, %3\n"
		"	sc.d	%1, %0, %2\n"
		"	bnez	%1, 1b"
			: "=&r" (result), "=&r" (tmp), "+A" (v->counter)
			: "Ir" (i)
			: "memory");

	/*  */
	smp_mb();
	return result;
}

unsigned long arch_accurate_xchg(unsigned long x, volatile void *ptr, int size)
{
	unsigned long ret;
	if (size == 4)
		ret = xchg((int*)ptr, (x));
	else if (size == 8)
		ret = xchg((long*)ptr, (x));
	else 
		BUG();
	/*  */
	smp_mb();
	return ret;
}

long arch_accurate_cmpxchg(struct accurate_counter *ptr, long old, long new)
{
	long oldval;
	/*  */
	smp_mb();

	oldval = cmpxchg(&((ptr)->counter), (old), (new));
	/*  */
	smp_mb();
	return oldval;
}
